package com.lifesting.tool.j2as3.visitor;

import java.util.List;
import java.util.PriorityQueue;
import java.util.Queue;

import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.AssertStatement;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.BreakStatement;
import org.eclipse.jdt.core.dom.ConstructorInvocation;
import org.eclipse.jdt.core.dom.ContinueStatement;
import org.eclipse.jdt.core.dom.DoStatement;
import org.eclipse.jdt.core.dom.EmptyStatement;
import org.eclipse.jdt.core.dom.EnhancedForStatement;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.ExpressionStatement;
import org.eclipse.jdt.core.dom.ForStatement;
import org.eclipse.jdt.core.dom.IfStatement;
import org.eclipse.jdt.core.dom.LabeledStatement;
import org.eclipse.jdt.core.dom.ReturnStatement;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
import org.eclipse.jdt.core.dom.SwitchCase;
import org.eclipse.jdt.core.dom.SwitchStatement;
import org.eclipse.jdt.core.dom.SynchronizedStatement;
import org.eclipse.jdt.core.dom.ThrowStatement;
import org.eclipse.jdt.core.dom.TryStatement;
import org.eclipse.jdt.core.dom.TypeDeclarationStatement;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
import org.eclipse.jdt.core.dom.WhileStatement;

import com.lifesting.tool.j2as3.action.NodeWriter;
import com.lifesting.tool.j2as3.action.Util;
import com.lifesting.tool.j2as3.action.NodeWriter.Writer;

public class StatementVisitor extends BodyVisitor {
	public static final String NO_BREAK="NOBREAK";
	
	public StatementVisitor(NodeWriter nodeWriter) {
		super(nodeWriter);
	}
	@Override
	protected void reset() {
		super.reset();
		
	}
	@Override
	public boolean visit(AssertStatement node) {
		return super.visit(node);
	}

	@Override
	public void endVisit(AssertStatement node) {
		super.endVisit(node);
	}
	@Override
	public boolean visit(Block node) {
		Writer writer = o(node);
		printIndents(writer);
		writer.print("{");
		writer.println();
		return true;
	}
	@Override
	public void endVisit(Block node) {
		Writer writer = o(node);
		printIndents(writer);
		Object lb = node.getProperty(NO_BREAK);
		if (lb != null && lb == Boolean.TRUE)
			writer.print("}");
		else
			writer.println("}");
	}
	@Override
	public boolean visit(BreakStatement node) {
		Writer writer = o(node);
		printIndents(writer);
		writer.print("break ");
		SimpleName label = node.getLabel();
		if (label != null){
			label.accept(this);
		}
		writer.println(";");
		return false;
	}
	@Override
	public void endVisit(BreakStatement node) {
		super.endVisit(node);
	}
	@Override
	public boolean visit(ConstructorInvocation node) {
		Writer writer = o(node);
		printIndents(writer);
		writer.print("this(");
		rightRecursiveVisit(node.arguments(),writer);
		writer.println(");");
		return false;
	}
	@Override
	public void endVisit(ConstructorInvocation node) {
		super.endVisit(node);
	}
	@Override
	public boolean visit(ContinueStatement node) {
		Writer writer = o(node);
		printIndents(writer);
		writer.print("continue ");
		SimpleName label = node.getLabel();
		if (label != null){
			label.accept(this);
		}
		writer.println(";");
		return false;
	}
	@Override
	public void endVisit(ContinueStatement node) {
		super.endVisit(node);
	}
	@Override
	public boolean visit(DoStatement node) {
		Writer writer = o(node);
		if (!Util.hasNoIndent(node))
			printIndents(writer);
		writer.println("do");
		node.getBody().setProperty(NO_BREAK, Boolean.TRUE);
		node.getBody().accept(this);
		writer.print("while (");
		node.getExpression().accept(this);
		writer.println(");");
		return false;
	}
	@Override
	public void endVisit(DoStatement node) {
		super.endVisit(node);
	}
	@Override
	public boolean visit(EmptyStatement node) {
		Writer writer = o(node);
		printIndents(writer);
		writer.println(";");
		return false;
	}
	@Override
	public void endVisit(EmptyStatement node) {
		super.endVisit(node);
	}
	@Override
	public boolean visit(EnhancedForStatement node) {
		Writer writer = o(node);
		printIndents(writer);
		writer.print("for each (");
		node.getParameter().accept(this);
		writer.print(")");
		node.getBody().accept(this);
		return false;
	}
	@Override
	public void endVisit(EnhancedForStatement node) {
		super.endVisit(node);
	}
	@Override
	public boolean visit(ExpressionStatement node) {
		printIndents(o(node));
		return true;
	}
	private void addContainerPointer(ASTNode node){
		NodeMessage nm = (NodeMessage) node.getProperty(MESSAGE_KEY);
		Writer writer = o(node);
		if (nm != null){
			String declare ="var "+nm.getSlot1()+" = new "+nm.getMsg()+"("+(nm.getSlot2() != null ? nm.getSlot2() : "")+");";
			String set_container = nm.getSlot1()+"."+BodyVisitor.POINTER_KEY+"=this"+(nm.getSlot3() != null ? nm.getSlot3() : "")+";";
			writer.headPrintln(set_container);
			writer.headPrintTab(level);
			writer.headPrintln(declare);
			writer.headPrintTab(level);
		}
	}
	@Override
	public void endVisit(ExpressionStatement node) {
		Writer writer = o(node);
		writer.println(";");
		//TODO consume message to add container pointer
		addContainerPointer(node);
	}
	@Override
	public boolean visit(ForStatement node) {
		Writer writer = o(node);
		if (!Util.hasNoIndent(node))
			printIndents(writer);
		writer.print("for(");
		rightRecursiveVisit(node.initializers(),writer);
		writer.print(";");
		Expression cond_expr = node.getExpression();
		if (cond_expr != null)
		{
			cond_expr.accept(this);
		}
		writer.print(";");
		rightRecursiveVisit(node.updaters(),writer);
		writer.println(")");
		node.getBody().accept(this);
		return false;
	}
	@Override
	public void endVisit(ForStatement node) {
		super.endVisit(node);
	}
	@Override
	public boolean visit(IfStatement node) {
		Writer writer = o(node);
		printIndents(writer);
		writer.print("if(");
		node.getExpression().accept(this);
		writer.println(")");
		node.getThenStatement().accept(this);
		Statement else_st = node.getElseStatement();
		if (else_st != null){
			printIndents(writer);
			writer.println("else");
			else_st.accept(this);
		}
		return false;
	}
	@Override
	public void endVisit(IfStatement node) {
		super.endVisit(node);
	}
	@Override
	public boolean visit(LabeledStatement node) {
		Writer writer = o(node);
		printIndents(writer);
		node.getLabel().accept(this);
		writer.print(":");
		Util.noIndent(node.getBody());
		node.getBody().accept(this);
		return false;
	}
	@Override
	public void endVisit(LabeledStatement node) {
		super.endVisit(node);
	}
	@Override
	public boolean visit(ReturnStatement node) {
		Writer writer = o(node);
		printIndents(writer);
		writer.print("return ");
		return true;
	}
	@Override
	public void endVisit(ReturnStatement node) {
		o(node).println(";");
		addContainerPointer(node);
	}
	@Override
	public boolean visit(SuperConstructorInvocation node) {
		Writer writer = o(node);
		printIndents(writer);
		Expression left_expr = node.getExpression();
		if (left_expr != null){
			left_expr.accept(this);
			writer.print(".");
		}
		writer.print("super(");
		rightRecursiveVisit(node.arguments(),writer);
		writer.println(");");
		return false;
	}
	@Override
	public void endVisit(SuperConstructorInvocation node) {
		super.endVisit(node);
	}
	@Override
	public boolean visit(SwitchCase node) {
		Writer writer = o(node);
		printIndents(writer);
		if (node.isDefault()){
			writer.print("default");
		}else{
			writer.print("case ");
		}
		return true;
	}
	@Override
	public void endVisit(SwitchCase node) {
		o(node).println(":");
	}
	@Override
	public boolean visit(SwitchStatement node) {
		Writer writer = o(node);
		printIndents(writer);
		writer.print("switch (");
		node.getExpression().accept(this);
		writer.println(")");
		printIndents(writer);
		writer.println("{");
		List sts = node.statements();
		for (Object s : sts){
			//extra statement indent
			if (!(s instanceof SwitchCase))	++level;
			((Statement)s).accept(this);
			if (!(s instanceof SwitchCase))	--level;
		}
		return false;
	}
	@Override
	public void endVisit(SwitchStatement node) {
		Writer writer = o(node);
		printIndents(writer);
		writer.println("}");
	}
	@Override
	public boolean visit(SynchronizedStatement node) {
		node.getBody().accept(this);
		return false;
	}
	@Override
	public void endVisit(SynchronizedStatement node) {
		super.endVisit(node);
	}
	@Override
	public boolean visit(ThrowStatement node) {
		Writer writer = o(node);
		printIndents(writer);
		writer.print("throw ");
		return true;
	}
	@Override
	public void endVisit(ThrowStatement node) {
		o(node).println(";");
	}
	@Override
	public boolean visit(TryStatement node) {
		Writer writer = o(node);
		printIndents(writer);
		writer.println("try");
		node.getBody().setProperty(NO_BREAK, Boolean.TRUE);
		node.getBody().accept(this);
		visitChildren(node.catchClauses());
		Block finally_block = node.getFinally();
		if (finally_block != null){
			writer.println("finally");
			finally_block.accept(this);
		}
		return false;
	}
	@Override
	public void endVisit(TryStatement node) {
		super.endVisit(node);
	}
	@Override
	public boolean visit(TypeDeclarationStatement node) {
		return super.visit(node);
	}
	@Override
	public void endVisit(TypeDeclarationStatement node) {
		super.endVisit(node);
	}
	@Override
	public boolean visit(VariableDeclarationStatement node) {
		Writer writer = o(node);
		printIndents(writer);
		visitChildren(node.modifiers());
		node.setProperty(TYPE_KEY, node.getType());
		writer.print("var ");
		rightRecursiveVisit(node.fragments(),writer);
		return false;
	}
	@Override
	public void endVisit(VariableDeclarationStatement node) {
		Writer writer = o(node);
		writer.println(";");;
		NodeMessage a_msg = (NodeMessage) node.getProperty(MESSAGE_KEY);
		if (a_msg != null){
			printIndents(writer);
			writer.println(a_msg.getMsg()+"."+BodyVisitor.POINTER_KEY+"=this"+(a_msg.getSlot3()!=null ? a_msg.getSlot3() : "")+";");
		}	
	}
	@Override
	public boolean visit(WhileStatement node) {
		Writer writer = o(node);
		if (!Util.hasNoIndent(node))
			printIndents(writer);
		writer.print("while (");
		node.getExpression().accept(this);
		writer.println(")");
		node.getBody().accept(this);
		return false;
	}
	@Override
	public void endVisit(WhileStatement node) {
		super.endVisit(node);
	}
	
	
	
	
	
	
	
}
